package com.tangcheng.adapter.db.mybatis.plugin.sensitive.processor;

import com.tangcheng.adapter.db.mybatis.plugin.sensitive.annotation.SensitiveField;
import com.tangcheng.adapter.db.mybatis.plugin.sensitive.service.IEncryptionAlgorithm;
import com.tangcheng.adapter.db.mybatis.plugin.sensitive.util.FieldHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class EncryptSensitiveField extends AbstractSensitiveField {

    public EncryptSensitiveField(IEncryptionAlgorithm encryptService) {
        this.encryptService = encryptService;
    }

    public Object handleObject(Object object) {
        if (object instanceof List) {
            List list = (List) object;
            Object result;
            if (FieldHelper.checkStringInCollection(list)) {
                result = this.fieldValueEncryptIfString(list);
            } else {
                result = this.handleList(list);
            }

            return result;
        } else if (FieldHelper.checkIfObject(object.getClass().getTypeName())) {
            return this.handleSingleObject(object);
        } else {
            return object instanceof String ? this.encryptService.encrypt(object.toString()) : object;
        }
    }

    public Object[] handle(ProceedingJoinPoint pjp) {
        log.debug("开始加密");
        Object[] args = pjp.getArgs();
        Object[] newArgs = new Object[args.length];
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Parameter[] parameter = methodSignature.getMethod().getParameters();
        int i = 0;

        for (int len = args.length; i < len; ++i) {
            Object temp = args[i];
            Parameter p = parameter[i];
            if (p.isAnnotationPresent(SensitiveField.class)) {
                newArgs[i] = this.handleObject(temp);
            } else {
                newArgs[i] = temp;
            }
        }

        return newArgs;
    }

    @Override
    public Object proceed(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object[] newArgs = this.handle(proceedingJoinPoint);
        return proceedingJoinPoint.proceed(newArgs);
    }

    @Override
    public void setFieldValue(Object object, Field field) {
        if (field.isAnnotationPresent(SensitiveField.class)) {
            try {
                field.setAccessible(true);
                Object val = field.get(object);
                if (val != null) {
                    String newVal = this.encryptService.encrypt(val.toString());
                    field.set(object, newVal);
                    log.info("敏感字段加密 字段：{} 明文：{} 密文：{}", field.getName(), val, newVal);
                }

                field.setAccessible(false);
            } catch (Exception e) {
                log.warn("加密失败 {}", e.getMessage());
            }
        }

    }

    private List<String> fieldValueEncryptIfString(List<String> collection) {
        List<String> result = new ArrayList<>(collection.size());
        collection.forEach((item) -> {
            if (StringUtils.isNotBlank(item)) {
                String newVal = this.encryptService.encrypt(item);
                result.add(newVal);
            } else {
                result.add(item);
            }

        });
        return result;
    }


}